﻿Imports System.Text
Imports System.Collections.ObjectModel

Namespace Compiler.Semantic

    ''' <summary>
    ''' Represents a qualifier of a name. Such as namespace or outer type name.
    ''' </summary>
    ''' <remarks>
    ''' Qulifier is constructed with a set of symbol. Each symbol has connector symbol used to connect its child symbol.
    ''' </remarks>
    Public NotInheritable Class Qualifier
        Inherits ReadOnlyCollection(Of QualifierSection)
        Implements IEquatable(Of Qualifier)

        Private m_cachedString As String

        Friend Sub New(ByVal sectionList As IList(Of QualifierSection))
            MyBase.New(sectionList)

            Debug.Assert(sectionList IsNot Nothing)

            Dim cacheStringBuilder As New StringBuilder
            For Each section In Me
                cacheStringBuilder.Append(section.Connector.ToString())
                cacheStringBuilder.Append(section.Name.ToString())
            Next

            m_cachedString = cacheStringBuilder.ToString()
        End Sub


        ''' <summary>
        ''' Returns a string that constructed by every qualifier section's symbol and connector in the order of high level first, 
        ''' low level after
        ''' </summary>
        ''' <returns>A string represents the qualifier</returns>
        Public Overrides Function ToString() As String
            Return m_cachedString
        End Function

        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj Is Nothing OrElse Not TypeOf obj Is Qualifier Then Return False

            Return Equals(TryCast(obj, Qualifier))
        End Function

        Public Overrides Function GetHashCode() As Integer
            Return m_cachedString.GetHashCode()
        End Function

        Public Overloads Function Equals(ByVal other As Qualifier) As Boolean Implements System.IEquatable(Of Qualifier).Equals
            'If other Is Nothing Then Return False

            'If other.Count <> Me.Count Then
            '    Return False
            'End If

            'Dim equal As Boolean = True
            'For i = 0 To Me.Count - 1
            '    equal = Me(i).Equals(other(i))
            '    If Not equal Then Exit For
            'Next

            'Return equal
            Return Equals(other, False)
        End Function

        Public Overloads Function Equals(ByVal other As Qualifier, ByVal ignoreConnector As Boolean) As Boolean
            If other Is Nothing Then Return False

            If other.Count <> Me.Count Then
                Return False
            End If

            Dim equal As Boolean = True

            If ignoreConnector Then
                For i = 0 To Me.Count - 1
                    equal = Me(i).Name.Equals(other(i).Name)
                    If Not equal Then Exit For
                Next
            Else
                For i = 0 To Me.Count - 1
                    equal = Me(i).Equals(other(i))
                    If Not equal Then Exit For
                Next
            End If

            Return equal
        End Function
    End Class

    Public Class QualifierBuilder
        Private m_sectionList As List(Of QualifierSection)

        Public Sub New()
            m_sectionList = New List(Of QualifierSection)
        End Sub

        Public Sub PushSection(ByVal section As QualifierSection)
            m_sectionList.Add(section)
        End Sub

        Public Sub PushTopLevelSection(ByVal sectionName As Symbol)
            PushSection(New QualifierSection With {.Name = sectionName, .Connector = QualifierSection.TopLevelConnector})
        End Sub

        Public Sub PushNamespaceSection(ByVal sectionName As Symbol)
            PushSection(New QualifierSection With {.Name = sectionName, .Connector = QualifierSection.NamespaceConnector})
        End Sub

        Public Sub PushTypeSection(ByVal sectionName As Symbol)
            PushSection(New QualifierSection With {.Name = sectionName, .Connector = QualifierSection.NamespaceConnector})
        End Sub

        Public Sub PushNestedTypeSection(ByVal sectionName As Symbol)
            PushSection(New QualifierSection With {.Name = sectionName, .Connector = QualifierSection.NestedTypeConnector})
        End Sub

        Public Sub PushMemberSection(ByVal sectionName As Symbol)
            PushSection(New QualifierSection With {.Name = sectionName, .Connector = QualifierSection.MemberConnector})
        End Sub

        Public Sub AppendQualifier(ByVal subQualifier As Qualifier)
            If subQualifier Is Nothing Then Return

            For Each subSection In subQualifier
                m_sectionList.Add(subSection)
            Next
        End Sub

        Public Sub AppendQualifier(ByVal subQualifier As Qualifier, ByVal changeFirstConnectorTo As Symbol)
            If subQualifier Is Nothing Then Return
            Dim changeConnector As Boolean = True
            For Each subSection In subQualifier
                If changeConnector Then
                    subSection.Connector = changeFirstConnectorTo
                    changeConnector = False
                End If
                m_sectionList.Add(subSection)
            Next
        End Sub

        Public Sub AddPrefix(ByVal prefix As QualifierSection)
            m_sectionList.Insert(0, prefix)
        End Sub

        Public Sub AddPrefixQualifier(ByVal prefix As Qualifier)
            m_sectionList.InsertRange(0, prefix)
        End Sub

        Public Function PopSection() As QualifierSection
            Dim stackTop As Integer = m_sectionList.Count
            Debug.Assert(stackTop > 0)
            Dim result = m_sectionList(stackTop - 1)
            m_sectionList.RemoveAt(stackTop - 1)

            Return result
        End Function

        Public Function BuildQualifier() As Qualifier
            Return New Qualifier(m_sectionList)
        End Function
    End Class

    Public Structure QualifierSection
        Implements IEquatable(Of QualifierSection)

        Public Shared ReadOnly NamespaceConnector As Symbol = Symbol.Get(".")
        Public Shared ReadOnly MemberConnector As Symbol = Symbol.Get(".")
        Public Shared ReadOnly NestedTypeConnector As Symbol = Symbol.Get("+")
        Public Shared ReadOnly ExternAliasConnector As Symbol = Symbol.Get("::")
        Public Shared ReadOnly TopLevelConnector As Symbol = Symbol.Get(String.Empty)

        Public Name As Symbol
        Public Connector As Symbol

        Public Overloads Function Equals(ByVal other As QualifierSection) As Boolean Implements System.IEquatable(Of QualifierSection).Equals
            Return Me.Name = other.Name AndAlso Me.Connector = other.Connector
        End Function

        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If Not TypeOf obj Is QualifierSection Then Return False
            Return Equals(CType(obj, QualifierSection))
        End Function

        Public Overrides Function GetHashCode() As Integer
            Return Name.GetHashCode Xor Connector.GetHashCode
        End Function

        Public Overrides Function ToString() As String
            Return Name.ToString() & Connector.ToString()
        End Function
    End Structure

End Namespace
